﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using SCM;
using Swift;
using Swift.Math;
using UnityEngine.AI;

public class MapUnit : MonoBehaviour, IEventHandler
{
    public Transform Attack01Stub;
    public Transform Attack02Stub;

    public AnimationPlayer AniPlayer
    {
        get
        {
            if (aniPlayer == null)
                aniPlayer = GetComponentInChildren<AnimationPlayer>();

            return aniPlayer;
        }
    } AnimationPlayer aniPlayer;

    // 带视野
    public bool WithVision { get; set; }

    // 是否显示选中效果
    public bool Selected
    {
        set
        {
            transform.Find("SelRing").gameObject.SetActive(value);
        }
    }

    Transform root = null;
    public Transform Root { get { if (root == null) root = transform.Find("Root"); return root; } }

    public bool ShowAttackRange
    {
        set
        {
            showAttackRange = value;
            if (attackRangeTransform != null)
                attackRangeTransform.gameObject.SetActive(value);
        }
    } bool showAttackRange = true;

    float nowModelDir = 0;
    Transform visionTransform;
    Transform attackRangeTransform;
    public Unit U
    {
        get { return u; }
        set
        {
            u = value;
            if (u != null)
            {
                var cfg = u.cfg;
                var sz = cfg.ShowSize <= 0 ? 1 : cfg.ShowSize;
                var s = sz * 2;
                transform.localScale = Vector3.one * (float)s;

                IsMine = u.Player == GameCore.Instance.MePlayer;
                RefreshColor();

                nowModelDir = -(float)u.Dir;
                transform.localRotation = Quaternion.Euler(0, nowModelDir, 0);

                visionTransform = transform.Find("Vision");
                RefreshVision();

                if (u.cfg.GuardingRange > 0 && u.cfg.ShowSize > 0)
                {
                    attackRangeTransform = transform.Find("AttackRange");
                    var ars = (float)(u.cfg.GuardingRange / u.cfg.ShowSize);
                    attackRangeTransform.localScale = new Vector3(ars, 0.1f, ars);
                }
                else
                    attackRangeTransform = null;
            }
        }
    } Unit u;

    public void RefreshColor()
    {
        var mrs = GetComponentsInChildren<MeshRenderer>();
        foreach (var mr in mrs)
        {
            if (!u.IsNeutral)
                mr.material.color = IsMine ? Color.blue : Color.red;
        }
    }

    public void RefreshVision()
    {
        if (u != null && WithVision && U.cfg.VisionRadius > 0)
        {
            var cfg = u.cfg;
            var sz = cfg.ShowSize <= 0 ? 1 : cfg.ShowSize;
            visionTransform.gameObject.SetActive(true);
            visionTransform.localScale = (u.cfg.IsBuilding && !u.BuildingCompleted) ?
                Vector3.one * (float)(1 + 50 / sz) :
                Vector3.one * (float)(cfg.VisionRadius / sz);
            visionTransform.localPosition = u.cfg.IsAirForce ? Vector3.up * 0.8f : Vector3.zero;
        }
        else if (visionTransform != null)
            visionTransform.gameObject.SetActive(false);
    }

    public MapGround MG = null;

    // 是否玩家控制的单位
    public bool IsMine
    {
        get { return isMine; }
        set
        {
            isMine = value;
            var skMats = gameObject.GetComponentsInChildren<SkinnedMeshRenderer>();
            foreach (var skMat in skMats)
            {
                var modelName = skMat.material.mainTexture.name;
                modelName = modelName.Substring(0, modelName.LastIndexOf("_"));
                var texName = modelName + (isMine || IsNeutral ? "_01" : "_02");

                // 因为之前就贴图路径命名和美术没有定好，所以这里有两种情况
                var tex = Resources.Load<Texture>(@"FBX\" + modelName + @"\Textures\" + texName);
                if (tex == null)
                    tex = Resources.Load<Texture>(@"FBX\" + modelName + @"_01\Textures\" + texName);

                if (tex != null)
                    skMat.material.mainTexture = tex;
            }
        }
    } bool isMine = false;

    // 是否是中立单位
    public bool IsNeutral { get { return u.Player == 0; } }

    public static bool YYY = false;

    public static float SpeedUp = 1;
    private void Update()
    {
        if (u == null)
            return;

        var dt = Time.deltaTime * SpeedUp;
        var toPos = u.Pos;
        var toDir = -(float)u.Dir;
        var fromPos = transform.localPosition;
        var v = u.cfg.MaxVelocity;

        // 同步位置
        var dx = (float)toPos.x - fromPos.x;
        var dy = (float)toPos.y - fromPos.z;
        var dist = (float)Math.Sqrt(dx * dx + dy * dy);
        if (dist > float.Epsilon && dist < v * 0.5f) // 加速播放可能会跳很远
        {
            var div = (float)v * dt / dist;
            if (div >= 1)
                transform.localPosition = new Vector3((float)toPos.x, transform.localPosition.y, (float)toPos.y);
            else
            {
                var x = transform.localPosition.x + dx * div;
                var y = transform.localPosition.z + dy * div;
                transform.localPosition = new Vector3(x, transform.localPosition.y, y);
            }
        }
        else
            transform.localPosition = new Vector3((float)toPos.x, transform.localPosition.y, (float)toPos.y);

        // 同步角度
        var dd = ((Fix64)(toDir - nowModelDir)).RangeIn180().Clamp(-720 * dt, 720 * dt);
        if (dd > float.Epsilon || dd < -float.Epsilon)
        {
            var me = GameCore.Instance.MePlayer;
            nowModelDir += (float)dd;
            transform.localRotation = Quaternion.Euler(0, nowModelDir, 0);
        }
    }

    public virtual void PlayAnimation(string ani)
    {
        var a = GetComponent<Animator>();
        if (a != null)
            a.Play(ani);
    }

    void SelectConstructingUnit(Vec2 pt, Vector3 wp)
    {
        var choices = GameCore.Instance.MeInfo.GetInBuildingUnit(u.UnitType);
        if (choices.Length == 0)
            return;

        var ui = UIManager.Instance.ShowTopUI("InBattleUI/SelectUnitUI", true) as SelectUnitUI;
        ui.Pos = pt;
        ui.Choices = choices;
        ui.ChoicesName = ui.Choices.ToArray((i, c, skip) =>
        {
            var ccfg = (u.Room as Room4Client).GetMyUnitConfig(c);
            return ccfg.DisplayName + "\r\n(" + ccfg.Cost + ")";
        });
        ui.Refresh();
        var pos = Vec2.Zero;
        ui.OnChoiceSel = (unitType) =>
        {
            var cfg = (u.Room as Room4Client).GetMyUnitConfig(unitType);
            var cost = cfg.Cost;
            if (GameCore.Instance.GetMyResource("Money") < cost)
            {
                AddTip("资源不足");
                return;
            }
            else if (cfg.IsAccessory && !u.Room.FindAccessoryPos(U, unitType, out pos))
            {
                AddTip("产能挂件已建满");
                return;
            }
            else if (cfg.IsAccessory)
            {
                // 同时只能有一个附件在建造
                foreach (var a in u.Accessories)
                {
                    if (!a.BuildingCompleted)
                    {
                        AddTip("需待上一个 产能挂件 建造完成");
                        return;
                    }
                }
            }

            if (cfg.IsBuilding && !cfg.IsAccessory)
            {
                if (!u.Room.CheckSpareSpace(U.Pos, cfg.RealSize))
                {
                    AddTip("建造位置被占用");
                    return;
                }

                var conn = GameCore.Instance.ServerConnection;
                var buff = conn.Send2Srv("ConstructBuilding");
                buff.Write(unitType);
                buff.Write(u.Pos);
                conn.End(buff);
            }
            else
            {
                var op = cfg.IsAccessory ? "ConstructAccessoryUnit" : "ConstructBattleUnit";
                var conn = GameCore.Instance.ServerConnection;
                var buff = conn.Send2Srv(op);
                buff.Write(U.UID);
                buff.Write(unitType);
                conn.End(buff);
            }
        };
    }

    // 点击生产单位
    public virtual void OnClick(Vec2 pt, Vector3 wp)
    {
        if (!MG.CheckInVision(pt))
        {
            // 点击视野外等同点击地面
            MG.OnClick(pt, wp);
            return;
        }
        else if (u.UnitType == "CCStub")
        {
            AddTip("矿点剩余资源: " + u.Hp);
            return;
        }
        else if (!IsMine || !U.cfg.IsBuilding)
        {
            // 点击非己方单位非建筑单位或者己方单位等同点击地面
            MG.OnClick(pt, wp);
            return;
        }
        
        if (!u.BuildingCompleted)
            ShowCancelSel(pt);
        else if (U.cfg.GenUnitTypes != null)
            SelectConstructingUnit(pt, wp);
    }

    // 长按选择升级
    public virtual void OnPress(Vec2 pt, Vector3 wp)
    {
        if (!MG.CheckInVision(pt))
        {
            AddTip("只能在视野内操作");
            return;
        }
        else if (u.UnitType == "CCStub")
        {
            SelectConstructingUnit(pt, wp);
            return;
        }
        else if (!IsMine)
            return;

        ShowLevelUpSel(pt);
    }

    void ShowCancelSel(Vec2 pt)
    {
        var ui = UIManager.Instance.ShowTopUI("InBattleUI/SelectUnitUI", true) as SelectUnitUI;
        ui.Pos = pt;
        ui.Choices = new string[] { "Cancel" };
        ui.ChoicesName = new string[] { "取消" };
        ui.Refresh();
        ui.OnChoiceSel = (toType) =>
        {
            if (U.BuildingCompleted)
                return;

            if (U.UnitType == "StarTrack" || U.UnitType == "Fortress")
            {
                AddTip("不可取消建筑升级");
                return;
            }
            
            var conn = GameCore.Instance.ServerConnection;
            var buff = conn.Send2Srv("CancelBuilding");
            buff.Write(U.UID);
            conn.End(buff);
        };
    }

    void ShowLevelUpSel(Vec2 pt)
    {
        var lvs = U.cfg.LevelUps;
        if (lvs == null || lvs.Length == 0)
            return;

        var choices = GameCore.Instance.MeInfo.GetBuildingLevelUp(U.UnitType);
        if (choices.Length == 0)
            return;

        var ui = UIManager.Instance.ShowTopUI("InBattleUI/SelectUnitUI", true) as SelectUnitUI;
        ui.Pos = pt;
        ui.Choices = choices;
        ui.ChoicesName = ui.Choices.ToArray((i, c, skip) =>
        {
            var ccfg = (U.Room as Room4Client).GetMyUnitConfig(c);
            return ccfg.DisplayName + "\r\n(" + ccfg.Cost + ")";
        });
        ui.Refresh();
        ui.OnChoiceSel = (toType) =>
        {
            if (!U.BuildingCompleted)
                return;

            var cfg = (U.Room as Room4Client).GetMyUnitConfig(toType);
            var cost = cfg.Cost;
            if (GameCore.Instance.GetMyResource("Money") < cost)
            {
                AddTip("资源不足");
                return;
            }
            else if (cfg.Prerequisites != null
                    && (U.Room as Room4Client).GetAllMyUnits((u) => u.BuildingCompleted && cfg.Prerequisites.FirstIndexOf(u.UnitType) >= 0).Length == 0)
            {
                AddTip("需要先建造 " + (U.Room as Room4Client).GetMyUnitConfig(cfg.Prerequisites[0]).DisplayName);
                return;
            }

            var conn = GameCore.Instance.ServerConnection;
            var buff = conn.Send2Srv("BuildingLevelUp");
            buff.Write(U.UID);
            buff.Write(toType);
            conn.End(buff);
        };
    }

    public virtual void OnDoubleClick(Vec2 pt, Vector3 wp)
    {
    }

    public virtual void OnDragStarted(Vec2 pt, Vector3 wp)
    {
        if (u.Player != GameCore.Instance.MePlayer)
            return;

        // 指挥中心或要塞拖动释放雷达，星轨拖动空投伞兵
        if (u.UnitType == "CommanderCenter" || u.UnitType == "Fortress" || u.UnitType == "StarTrack")
        {
            MG.RadarSelFlag.SetActive(true);
            MG.RadarSelFlag.transform.localPosition = wp + Vector3.up;
        }
    }

    public virtual void OnDragging(Vec2 from, Vector3 fromWp, Vec2 nowPt, Vector3 nowWp)
    {
        UIManager.Instance.ShowTopUI("InBattleUI/SelectUnitUI", false);
        MG.RadarSelFlag.transform.localPosition = nowWp + Vector3.up;
    }

    public virtual void DoDragEnded(Vec2 from, Vector3 fromWp, Vec2 to, Vector3 toWp)
    {
        if (!u.cfg.IsBuilding || !u.BuildingCompleted || u.Player != GameCore.Instance.MePlayer)
            return;

        if (u.UnitType == "CommanderCenter" || u.UnitType == "Fortress" || u.UnitType == "StarTrack")
            ReleaseCarrier(from, fromWp, to, toWp);
        else
            ReleaseBattleUnits(from, fromWp, to, toWp);
    }

    public void ReleaseBattleUnits(Vec2 from, Vector3 fromWp, Vec2 to, Vector3 toWp)
    {
        var conn = GameCore.Instance.ServerConnection;
        var buff = conn.Send2Srv("ReleaseBattleUnits");
        buff.Write(u.UID);
        buff.Write(new Vec2((int)toWp.x, (int)toWp.z));
        conn.End(buff);
    }

    public void ReleaseCarrier(Vec2 from, Vector3 fromWp, Vec2 to, Vector3 toWp)
    {
        MG.RadarSelFlag.SetActive(false);

        if (u.cfg.IsBuilding && !u.BuildingCompleted)
            return;

        // 指挥中心或要塞拖动释放雷达，星轨拖动空投伞兵
        if ((u.UnitType != "CommanderCenter" && u.UnitType != "Fortress" && u.UnitType != "StarTrack")
                || u.Player != GameCore.Instance.MePlayer)
            return;

        var radarType = u.UnitType == "StarTrack" ? "SoldierCarrier" : "RadarSign";

        // 没伞兵就用雷达
        var meInfo = GameCore.Instance.MeInfo;
        if (meInfo.GetCardLv(radarType) <= 0 && radarType == "SoldierCarrier")
            radarType = "RadarSign";

        // 还没有就算了
        if (meInfo.GetCardLv(radarType) <= 0)
            return;

        var cfg = (U.Room as Room4Client).GetMyUnitConfig(radarType);
        var cost = cfg.Cost;
        var money = GameCore.Instance.GetMyResource("Money");
        if (money < cost)
        {
            AddTip("资源不足");
            return;
        }

        // 雷达和伞兵是不同的操作指令
        var conn = GameCore.Instance.ServerConnection;
        if (radarType == "SoldierCarrier")
        {
            var buff = conn.Send2Srv("DropSoldierFromCarrier");
            buff.Write(new Vec2((int)toWp.x, (int)toWp.z));
            conn.End(buff);
        }
        else
        {
            var buff = conn.Send2Srv("ConstructBuilding");
            buff.Write(radarType);
            buff.Write(new Vec2((int)toWp.x, (int)toWp.z));
            conn.End(buff);
        }
    }

    NavMeshAgent nma = null;
    private void Awake()
    {
        nma = GetComponent<NavMeshAgent>();
        if (nma != null)
            nma.enabled = false;
    }

    void AddTip(string tip)
    {
        UIManager.Instance.Tips.AddTip(tip);
    }

    void AddSmallTip(string tip)
    {
        UIManager.Instance.Tips.AddSmallTip(tip);
    }
}
